import { createStore, Commit } from 'vuex'
import axios, { AxiosRequestConfig } from 'axios'
import { arrToObj, objToArr } from './helper'

// 图片信息
export interface ImageProps {
  _id?: string;
  url?: string;
  createdAt?: string;
  fitUrl?: string;
}
// 请求返回数据类型,添加一个更好的类型，来指示一个默认的空对象类型
// 写法：T = Record<string, unknown> 或者 T = { [key: string]: any }
export interface ResponseType<T = { [key: string]: any }> {
  code: number;
  msg: string;
  data: T;
}
// 用户信息
export interface UserProps {
  _id?: string;
  email?: string;
  nickName?: string;
  description?: string;
  avatar?: ImageProps;
  column?: string
  isLogin: boolean;
}
// 专栏列表信息
export interface ColumnProps {
  _id: string;
  title: string;
  avatar?: ImageProps;
  author: string;
  createdAt: string;
  featured: boolean;
  description: string;
}
// 文章信息
export interface PostProps {
  _id?: string;
  title: string;
  excerpt?: string;
  content: string;
  image?: ImageProps | string;
  column: string;
  author?: UserProps | string;
  createdAt?: string;
  isHTML?: boolean;
}
// 全局通用错误信息
export interface GlobalErrorProps {
  status: boolean;
  message?: string;
}
// 整合文章和专栏列表数据类型,变为索引类型
interface ListProps<T> {
  [id: string]: T;
}
export interface GlobalColumnsProps {
  data: ListProps<ColumnProps>;
  currentPage: number;
  total?: number;
}
export interface GlobalPostsProps {
  data: ListProps<PostProps>;
  loadedColumns: ListProps<{ total?: number; currentPage?: number }>;
}
// 全局数据信息
export interface GlobalDataProps {
  user: UserProps;
  // total: 专栏总数
  columns: GlobalColumnsProps;
  posts: GlobalPostsProps;
  loading: boolean;
  token: string;
  error: GlobalErrorProps;
}
// 封装函数：提取异步获取数据并提交到mutations函数中
const getAndCommit = async (url: string, mutationName: string, commit: Commit) => {
  const { data } = await axios.get(url)
  commit(mutationName, data)
  return data
}
const postAndCommit = async (url: string, mutationName: string, commit: Commit, payload: any) => {
  const { data } = await axios.post(url, payload)
  commit(mutationName, data)
  return data
}
// 发送异步请求，默认是get请求
const AsyncAndCommit = async (url: string, mutationName: string,
  commit: Commit, config: AxiosRequestConfig = { method: 'get' }, extraData?: any) => {
  const { data } = await axios(url, config)
  // 判断是否需要返回额外的数据
  if (extraData) {
    commit(mutationName, { data, extraData })
  } else {
    commit(mutationName, data)
  }
  return data
}

const store = createStore<GlobalDataProps>({
  state: {
    user: { isLogin: false },
    columns: { data: {}, currentPage: 0, total: 0 },
    posts: { data: {}, loadedColumns: {} },
    loading: false,
    // 1、初始化store时获取存储在localStorage中的token
    token: localStorage.getItem('token') || '',
    error: { status: false }
  },
  mutations: {
    // 登录
    // login (state) {
    //   state.user = { ...state.user, isLogin: true }
    // },
    // 创建文章
    createPost (state, newPost) {
      state.posts.data[newPost._id] = newPost
    },
    // 更新文章
    updatePost (state, { data }) {
      // 找到对应的文章进行替换
      state.posts.data[data._id] = data
    },
    // 删除文章
    deletePost (state, { data }) {
      // poost数组中当前删除的文章信息
      delete state.posts.data[data._id]
    },
    // 获取专栏信息保存到state中的columns
    fetchColumns (state, rawData) {
      const { data } = state.columns
      const { list, count, currentPage } = rawData.data
      state.columns = {
        // 每次获取跟新新的值
        data: { ...data, ...arrToObj(list) },
        total: count,
        currentPage: currentPage * 1
      }
    },
    // 获取专栏下的文章信息保存到state中的columns中
    fetchColumn (state, rawData) {
      state.columns.data[rawData.data._id] = rawData.data
    },
    // 获取专栏下的文章信息保存到state中的posts中
    fetchColumnsPosts (state, { data: rawData, extraData: columnId }) {
      // 进行数据展开后，新增
      const { data, loadedColumns } = state.posts
      const { list, count, currentPage } = rawData.data
      const listData = list as PostProps[]
      state.posts.data = { ...data, ...arrToObj(listData) }
      loadedColumns[columnId] = {
        total: count,
        currentPage
      }
    },
    fetchCurrentUser (state, rawData) {
      state.user = { isLogin: true, ...rawData.data }
    },
    fetchPost (state, rawData) {
      state.posts.data[rawData.data._id] = rawData.data
    },
    // 更新个人专栏信息
    updateColumn (state, { data }) {
      state.columns.data[data._id] = data
    },
    // 更新用户信息
    updateUser (state, { data }) {
      state.user = { isLogin: true, ...data }
    },
    // 设置数据加载loading的值
    setLoading (state, status: boolean) {
      state.loading = status
    },
    // 设置错误状态和信息
    setError (state, e: GlobalErrorProps) {
      state.error = e
    },
    // 登录
    login (state, rawData) {
      const { token } = rawData.data
      state.token = token
      // 设置持久化登录localStorage中的值
      localStorage.setItem('token', token)
      // 设置请求头的Authorization
      axios.defaults.headers.common.Authorization = `Bearer ${token}`
    },
    // 退出登录
    logout (state) {
      state.token = ''
      state.user = { isLogin: false }
      localStorage.removeItem('token')
      delete axios.defaults.headers.common.Authorization
    }
  },
  actions: {
    // 获取所有专栏信息
    fetchColumns ({ state, commit }, params = {}) {
      // 获取请求参数，没有传递使用默认值
      const { currentPage = 1, pageSize = 6 } = params
      if (state.columns.currentPage < currentPage) {
        return AsyncAndCommit(`/columns?currentPage=${currentPage}&pageSize=${pageSize}`, 'fetchColumns', commit)
      }
    },
    // 获取单个专栏信息
    fetchColumn ({ state, commit }, cid: string) {
      const cIdArr = Object.keys(state.columns.data)
      if (!cIdArr.includes(cid)) {
        return AsyncAndCommit(`/columns/${cid}`, 'fetchColumn', commit)
      }
    },
    // 获取专栏下的文章信息
    fetchColumnsPosts ({ state, commit }, params = {}) {
      const { cid, currentPage = 1, pageSize = 5 } = params
      const { loadedColumns } = state.posts
      const loadedCurrentPage = (loadedColumns[cid] && loadedColumns[cid].currentPage) || 0
      // Object.keys： 获取map的键
      // 存储的数据不包含当前专栏下的文章信息或者
      if (!Object.keys(loadedColumns).includes(cid) || loadedCurrentPage < currentPage) {
        return AsyncAndCommit(`/columns/${cid}/posts?currentPage=${currentPage}&pageSize=${pageSize}`, 'fetchColumnsPosts', commit, { method: 'get' }, cid)
      }
    },
    // 获取当前用户信息
    fetchCurrentUser ({ commit }) {
      return AsyncAndCommit('/user/current', 'fetchCurrentUser', commit)
    },
    // 根据文章id获取文章信息
    fetchPost ({ state, commit }, pid: string) {
      const currentPost = state.posts.data[pid]
      // 文章信息不存在进行请求
      if (!currentPost || !currentPost.content) {
        return AsyncAndCommit(`/posts/${pid}`, 'fetchPost', commit)
      } else {
        // 数据存在，返回构造的Promise返回数据
        Promise.resolve({ data: currentPost })
      }
    },
    // 创建文章
    createPost ({ commit }, payload) {
      return AsyncAndCommit('/posts', 'createPost', commit, {
        method: 'post',
        data: payload
      })
    },
    // 更新文章
    updatePost ({ commit }, { id, payload }) {
      return AsyncAndCommit(`/posts/${id}`, 'updatePost', commit, {
        method: 'patch',
        data: payload
      })
    },
    // 删除文章
    deletePost ({ commit }, pid: string) {
      return AsyncAndCommit(`/posts/${pid}`, 'deletePost', commit, { method: 'delete' })
    },
    // 更新个人专栏信息
    updateColumn ({ commit }, { cid, payload }) {
      return AsyncAndCommit(`/columns/${cid}`, 'updateColumn', commit, { method: 'patch', data: payload })
    },
    // 更新个人信息
    updateUser ({ commit }, { id, payload }) {
      return AsyncAndCommit(`/user/${id}`, 'updateUser', commit, { method: 'patch', data: payload })
    },
    // 登录
    login ({ commit }, payload) {
      return AsyncAndCommit('/user/login', 'login', commit, {
        method: 'post',
        data: payload
      })
    },
    // 组合actions：登录并且获取当前用户的信息
    loginAndFetchCurrentUser ({ dispatch }, payload) {
      return dispatch('login', payload).then(() => {
        return dispatch('fetchCurrentUser')
      })
    }
  },
  getters: {
    // 通过专栏id获取专栏信息，返回一个函数
    getColumnById: (state) => (id: string) => {
      return state.columns.data[id]
    },
    // 通过专栏id获取专栏下的文章信息，返回一个函数
    getPostsByCid: (state) => (cid: string) => {
      return objToArr(state.posts.data).filter(p => p.column === cid)
    },
    // 根据文章id获取文章信息
    getCurrentPost: (state) => (pid: string) => {
      return state.posts.data[pid]
    },
    // 获取所有专栏列表信息
    getColumns: (state) => {
      return objToArr(state.columns.data)
    },
    // 获取专栏文章的当前页
    getPostsCurrentPageByCid: (state) => (cid: string) => {
      if (state.posts.loadedColumns[cid]) {
        return state.posts.loadedColumns[cid].currentPage
      } else {
        return 0
      }
    },
    // 获取专栏文章的总数量
    getPostsCountByCid: (state) => (cid: string) => {
      if (state.posts.loadedColumns[cid]) {
        return state.posts.loadedColumns[cid].total
      } else {
        return 0
      }
    }
  }
})

export default store
